home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / GUSI / GUSIBuffer.cp < prev    next >
Encoding:
Text File  |  1993-11-11  |  4.7 KB  |  280 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIBuffer.cp    -    Circular buffers and Scatter/Gather
  4. Author    :    Matthias Neeracher
  5. Started    :    01Aug92                                Language    :    MPW C/C++
  6. Modified    :    02Aug92    MN    Deferred procedures
  7.                 23Aug92    MN    Optimize buffer size for empty buffers
  8.                 10Feb93    MN    The above was incorrect, next attempt
  9.                 17Jul93    MN    proc -> defproc
  10. Last        :    17Jul93
  11. *********************************************************************/
  12.  
  13. #ifndef GUSI_BUFFER_DEBUG
  14. #define NDEBUG
  15. #endif
  16.  
  17. #include "GUSI_P.h"
  18.  
  19. /**************************** RingBuffer ****************************/
  20.  
  21. #ifndef NDEBUG
  22. int RingDist(Ptr start, Ptr end, Ptr from, Ptr to)
  23. {
  24.     if (from > to)
  25.         return RingDist(start, end, from, end)+RingDist(start, end, start, to);
  26.     else
  27.         return to-from;
  28. }
  29.  
  30. #define RINGEQ(from, to, val)    \
  31.     (RingDist(buffer, endbuf, (from), (to)) == ((val)%(endbuf-buffer)))
  32. #define INVAR                                    \
  33.     (    (free >= 0)                             \
  34.     && (valid >= 0)                             \
  35.     &&    RINGEQ(consume, produce, valid+spare) \
  36.     &&    RINGEQ(produce, consume, free))
  37. #endif
  38.  
  39. RingBuffer::RingBuffer(u_short bufsiz)
  40. {
  41.     buffer    =    NewPtr(bufsiz);
  42.     endbuf    =    buffer+bufsiz;
  43.     consume    =    buffer;
  44.     produce    =    buffer;
  45.     free        =    bufsiz;
  46.     valid        =    0;
  47.     spare        =    0;
  48.     lock        =    false;
  49.     defproc    =    nil;
  50.     
  51.     assert(INVAR);
  52.     assert(endbuf - buffer == bufsiz);
  53. }
  54.  
  55. RingBuffer::~RingBuffer()
  56. {
  57.     Defer();
  58.     if (buffer)
  59.         DisposPtr(buffer);
  60. }
  61.  
  62. Ptr RingBuffer::Producer(long & len)
  63. {
  64.     Defer();
  65.     
  66. #ifndef NDEBUG
  67.     long    oldlen    =    len;
  68. #endif
  69.  
  70.     if (!valid) {
  71.         produce = buffer;
  72.         consume = buffer;
  73.         spare   = 0;
  74.     }
  75.     
  76.     u_short    streak    =    endbuf - produce;
  77.     Ptr        res        =    produce;
  78.     
  79.     if (streak >= free)
  80.         streak = free;
  81.     else if (streak < (free >> 1) && streak < len) {
  82.         spare     =  streak;
  83.         produce    =    buffer;
  84.         free        -=    spare;
  85.         streak    =    free;
  86.         res         =    produce;
  87.     }
  88.     
  89.     if (len > streak)
  90.         len    =    streak;
  91.     
  92.     assert(INVAR);
  93.     assert(len <= oldlen);
  94.     
  95.     Undefer();
  96.     
  97.     return res;
  98. }
  99.  
  100. Ptr RingBuffer::Consumer(long & len)
  101. {
  102.     Defer();
  103.     
  104. #ifndef NDEBUG
  105.     long    oldlen    =    len;
  106. #endif
  107.  
  108.     u_short    streak    =    endbuf - consume - spare;
  109.     Ptr        res        =    consume;
  110.     
  111.     if (streak > valid)
  112.         streak = valid;
  113.     if (len > streak)
  114.         len    =    streak;
  115.     
  116.     assert(INVAR);
  117.     assert(len <= oldlen);
  118.     
  119.     Undefer();
  120.     
  121.     return res;
  122. }
  123.  
  124. void RingBuffer::Validate(long len)
  125. {
  126.     Defer();
  127.     
  128.     valid     += (unsigned short) len;
  129.     free        -=    (unsigned short) len;
  130.     produce    +=    len;
  131.     
  132.     if (produce == endbuf)
  133.         produce    =    buffer;
  134.     
  135.     assert(INVAR);
  136.     
  137.     Undefer();
  138. }
  139.  
  140. void RingBuffer::Invalidate(long len)
  141. {
  142.     Defer();
  143.     
  144.     free         += (unsigned short) len;
  145.     valid        -=    (unsigned short) len;
  146.     consume    +=    len;
  147.     
  148.     if (consume == endbuf-spare) {
  149.         consume    =    buffer;
  150.         spare        =    0;
  151.     } else if (!valid && free == len)    {        // Maximize streak for empty buffer
  152.         consume    =    buffer;
  153.         produce    =    buffer;
  154.     }
  155.     
  156.     assert(INVAR);
  157.     
  158.     Undefer();
  159. }
  160.  
  161. void RingBuffer::Consume(Ptr to, long & len)
  162. {
  163. #ifndef NDEBUG
  164.     Ptr    oldto        =    to;
  165.     long    oldlen    =    len;
  166. #endif
  167.  
  168.     long    part;
  169.     long    rest;
  170.     Ptr    buf;
  171.     
  172.     for (rest = len; (part = rest) && valid; rest -= part)    {
  173.         buf    =    Consumer(part);
  174.         BlockMove(buf, to, part);
  175.         Invalidate(part);
  176.         to        += part;
  177.     }
  178.     
  179.     len    -=    rest;
  180.     
  181.     assert(INVAR);
  182.     assert(len <= oldlen);
  183.     assert(to-oldto == len);
  184. }
  185.  
  186. void RingBuffer::Produce(Ptr from, long & len)
  187. {
  188. #ifndef NDEBUG
  189.     Ptr    oldfrom    =    from;
  190.     long    oldlen    =    len;
  191. #endif
  192.  
  193.     long    part;
  194.     long    rest;
  195.     Ptr    buf;
  196.     
  197.     for (rest = len; (part = rest) && free; rest -= part)    {
  198.         buf    =    Producer(part);
  199.         BlockMove(from, buf, part);
  200.         Validate(part);
  201.         
  202.         from    += part;
  203.     }
  204.     
  205.     len    -=    rest;
  206.     
  207.     assert(INVAR);
  208.     assert(len <= oldlen);
  209.     assert(from-oldfrom == len);
  210. }
  211.  
  212. /************************** Scatter/Gather **************************/
  213.  
  214. ScattGath::ScattGath(const struct iovec *iov, int cnt)    {
  215.     io        =    iov;
  216.     count    =    cnt;
  217.  
  218.     if (count < 1)    {
  219.         buf        =    nil;
  220.         len        =    0;
  221.         scratch    =    nil;
  222.     } else if (count == 1)    {    
  223.         buf        =    (void *) iov->iov_base;
  224.         len        =    (int)    iov->iov_len;
  225.         scratch    =    nil;
  226.     } else {
  227.         for (len = 0; count--; ++iov)
  228.             len += (int) iov->iov_len;
  229.         
  230.         scratch = NewHandle(len);
  231.         
  232.         if (scratch)    {
  233.             HLock(scratch);
  234.             buf    =    (void *) *scratch;
  235.         } else
  236.             buf     =    nil;
  237.     }
  238. }
  239.  
  240. ScattGath::~ScattGath()
  241. {
  242.     if (scratch)
  243.         DisposHandle(scratch);
  244. }
  245.  
  246. Scatterer::Scatterer(const struct iovec *iov, int count) 
  247.     : ScattGath(iov, count)
  248. {
  249. }
  250.  
  251. Scatterer::~Scatterer()
  252. {
  253.     int    sect;
  254.     
  255.     if (count > 1 && buf)
  256.         for (char * bptr = (char *) buf; count-- && len; ++io)    {
  257.             sect    =    min(len, io->iov_len);
  258.             
  259.             memcpy(io->iov_base, bptr, sect);
  260.             
  261.             bptr    +=    sect;
  262.             len     -=    sect;
  263.         }
  264. }
  265.  
  266. Gatherer::Gatherer(const struct iovec *iov, int count) 
  267.     : ScattGath(iov, count)
  268. {
  269.     if (count > 1 && buf)
  270.         for (char * bptr = (char *) buf; count--; ++iov)    {
  271.             memcpy(bptr, iov->iov_base, iov->iov_len);
  272.             
  273.             bptr    +=    iov->iov_len;
  274.         }
  275. }
  276.  
  277. Gatherer::~Gatherer()
  278. {
  279. }
  280.